package com.javaeedev.junit;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.FinderException;
import javax.ejb.NoSuchEntityException;
import javax.naming.InitialContext;
import javax.sql.DataSource;

/**
 * BMP
 */
public class ProductBean implements EntityBean {

    public static final String JNDI_DATASOURCE = "java:comp/env/jdbc/datasouce";

    private String productId;
    private String name;
    private double price;

    private EntityContext context;
    private DataSource dataSource;

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    public String ejbCreate(String productId, String name, double price) throws CreateException {
        try {
            insertRow(productId, name, price);
        }
        catch (Exception ex) {
            throw new CreateException(ex.getMessage());
        }
        this.productId = productId;
        this.name = name;
        this.price = price;
        return productId;
    }

    public String ejbFindByPrimaryKey(String primaryKey) throws FinderException {
        boolean found;

        try {
            found = selectByPrimaryKey(primaryKey);
        }
        catch (Exception ex) {
            throw new FinderException(ex.getMessage());
        }
        if(found)
            return primaryKey;
        else
            throw new FinderException("Primary key: " + primaryKey);
    }

    public void ejbRemove() {
        try {
            deleteRow(productId);
        }
        catch(Exception ex) {
            throw new EJBException(ex.getMessage());
        }
    }

    public void setEntityContext(EntityContext context) {
        this.context = context;
        try {
            InitialContext ic = new InitialContext();
            dataSource = (DataSource) ic.lookup(JNDI_DATASOURCE);
        }
        catch (Exception ex) {
            throw new EJBException(ex.getMessage());
        }
    }

    public void unsetEntityContext() {
        this.context = null;
    }

    public void ejbActivate() {
        productId = (String)context.getPrimaryKey();
    }

    public void ejbPassivate() {
        productId = null;
    }

    public void ejbLoad() {
        try {
            loadRow();
        }
        catch (Exception ex) {
            throw new EJBException(ex.getMessage());
        }
    }

    public void ejbStore() {
        try {
            storeRow();
        }
        catch(Exception ex) {
            throw new EJBException(ex.getMessage());
        }
    }

    public void ejbPostCreate(String productId, String name, double price) {}

    /*********************** Database Routines *************************/

    private void insertRow(String productId, String name, double price) throws SQLException {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("insert into product values(?, ?, ?)");
            ps.setString(1, productId);
            ps.setString(2, name);
            ps.setDouble(3, price);
            ps.executeUpdate();
        }
        finally {
            close(ps);
            close(conn);
        }
    }

    private void deleteRow(String productId) throws SQLException {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("delete from product where productId=?");
            ps.setString(1, productId);
            ps.executeUpdate();
        }
        finally {
            close(ps);
            close(conn);
        }
    }

    private boolean selectByPrimaryKey(String primaryKey) throws SQLException {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("select productId from product where productId=?");
            ps.setString(1, primaryKey);
            rs = ps.executeQuery();
            return rs.next();
        }
        catch (Exception e) {
            return false;
        }
        finally {
            close(rs);
            close(ps);
            close(conn);
        }
    }

    private void loadRow() throws SQLException {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("select name, price from product where productId=?");
            ps.setString(1, productId);
            rs = ps.executeQuery();
            if (rs.next()) {
                name = rs.getString(1);
                price = rs.getDouble(2);
            }
            else
                throw new NoSuchEntityException();
        }
        finally {
            close(rs);
            close(ps);
            close(conn);
        }
    }

    private void storeRow() throws SQLException {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("update product set name=?, price=? where productId=?");
            ps.setString(1, name);
            ps.setDouble(2, price);
            ps.setString(3, productId);
            if(ps.executeUpdate()==0) {
                throw new EJBException();
            }
        }
        finally {
            close(ps);
            close(conn);
        }
   }

    private void close(Connection conn) {
        if(conn!=null) {
            try {
                conn.close();
            }
            catch(SQLException e) {}
        }
    }

    private void close(PreparedStatement ps) {
        if(ps!=null) {
            try {
                ps.close();
            }
            catch(SQLException e) {}
        }
    }

    private void close(ResultSet rs) {
        if(rs!=null) {
            try {
                rs.close();
            }
            catch(SQLException e) {}
        }
    }
}
